import localForage from "localforage";
const getItemMap = {
  "[object Map]": (value: any) => {
    return new Map(Object.entries(value));
  },
};
const setItemMap = {
  "[object Map]": async (key: string, value: any) => {
    await localForage.setItem(
      key,
      JSON.stringify({
        type: "[object Map]",
        value: [...value.entries()].reduce(
          (obj, [key, value]) => ((obj[key] = value), obj),
          {}
        ),
      })
    );
  },
};
const getItemValue = (key: string) => {
  return new Promise((resolve): any => {
    localForage.getItem(key).then((jsonStr: any) => {
      const data = JSON.parse(jsonStr);
      if (!data?.type || !data?.value) {
        return resolve(null);
      }
      const func = getItemMap[data?.type as keyof typeof getItemMap];
      if (func) {
        return resolve(func(data?.value));
      } else {
        return resolve(data.value);
      }
    });
  });
};
const setItemValue = async (key: string, value: any) => {
  const type = Object.prototype.toString.call(value) as keyof typeof getItemMap;
  const func = setItemMap[type as keyof typeof getItemMap];
  if (func) {
    await func(key, value);
  } else {
    await localForage.setItem(key, JSON.stringify({ type, value }));
  }
  const version = localStorage.getItem(key);
  localStorage.setItem(key, String(Number(version) + 1));
};
export const useMyLocalStorage = <T>(key: string, initialValue: T) => {
  const value = ref<any>(initialValue);
  getItemValue(key).then((data) => {
    if (data) {
      value.value = data;
    }
  });
  const unwatch = ref();
  const setupWatch = () => {
    const unwatch = watch(
      () => value.value,
      async (newValue) => {
        await setItemValue(key, newValue);
      },
      {
        deep: true,
      }
    );
    return unwatch;
  };
  unwatch.value = setupWatch();
  window.addEventListener("storage", (e) => {
    if (key === e.key) {
      getItemValue(e.key).then((data) => {
        unwatch.value();
        if (data) {
          value.value = data;
        }
        unwatch.value = setupWatch();
      });
    }
  });
  return value as Ref<T>;
};
